package newcoder_exp.justPractise;

import java.util.*;

import org.junit.Test;

public class NC137 {
    class Solution1 {
        /**
         * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可 返回表达式的值
         * 
         * @param s string字符串 待计算的表达式
         * @return int整型
         */
        public int solve(String s) {
            if (s == null || s.length() == 0)
                return 0;
            Stack<Character> cals = new Stack<>();
            Stack<Integer> nums = new Stack<>();
            int idx = 0;
            char last = '#';
            while (idx < s.length()) {
                char c = s.charAt(idx);
                if (isDigit(c)) {
                    if (isDigit(last)) {
                        int a = nums.pop();
                        nums.push(a * 10 + (c - '0'));
                    } else nums.push(c - '0');
                } else {
                    if (c == '(') { // 无脑压栈
                        cals.push(c);
                    } else if (c == '*' || c == '/') {
                        char t;
                        if (cals.isEmpty() || (t = cals.peek()) == '(') {
                            cals.push(c);
                        } else {
                            // 只有可能是加减
                           /*  int b = s.charAt(++idx) - '0';
                            int a = nums.pop();
                            nums.push(calc(a, b, c)); */
                            while (!cals.isEmpty() && ((t = cals.peek()) == '*' || t == '/')) {
                                int b = nums.pop();
                                int a = nums.pop();
                                nums.push(calc(a, b, t));
                                cals.pop();
                            }
                            cals.push(c);
                        }
                    } else if (c == '+' || c == '-') {
                        char t;
                        while (!cals.isEmpty() && ((t = cals.peek()) == '*' || t == '/' || t == '+' || t == '-')) {
                            int b = nums.pop();
                            int a = nums.pop();
                            nums.push(calc(a, b, t));
                            cals.pop();
                        }
                        cals.push(c);
                    } else {
                        char t;
                        int b = nums.pop(), a;
                        while ((t = cals.pop()) != '(') {
                            a = nums.pop();
                            b = calc(a, b, t);
                        }
                        nums.push(b);
                    }
                }
                idx++;
                last = c;
            }

            while (!cals.isEmpty()) {
                char c = cals.pop();
                int b = nums.pop(),
                a = nums.pop();
                nums.push(calc(a, b, c));
            }

            return nums.peek();

        }

        public int  calc(int a, int b, char c) {
            switch (c) {
                case '+':
                    return a + b;
                case '-':
                    return a - b;
                case '*':
                    return a * b;
                case '/':
                    if (b == 0)
                        return Integer.MIN_VALUE;
                    return a / b;
                default:
                    return a + b;
            }
        }

        public boolean isDigit(char c) {
            return c >= '0' && c <= '9';
        }
    }

    class Solution {

        Map<Character, int[]> map = new HashMap<>();
        class Cal {
            char calc;
            boolean inStack;
            public Cal(char calc, boolean inStack) {
                this.calc = calc;
                this.inStack = inStack;
            }

            public int getPriority() {
                if (this.inStack)
                    return map.get(this.calc)[1];
                else
                    return map.get(this.calc)[0];
            }
        }

        public int solve(String s) {
            if (s == null || s.length() == 0)
                return 0;
            Stack<Cal> cals = new Stack<>();
            Stack<Integer> nums = new Stack<>();

            map.put('+', new int[]{2, 3});
            map.put('-', new int[]{2, 3});
            map.put('*', new int[]{4, 5});
            map.put('/', new int[]{4, 5});
            map.put('(', new int[]{8, 1});
            map.put(')', new int[]{1, 8});

            int idx = 0, a, b;
            char c, last = '#', l;
            Cal t;
            while (idx < s.length()) {
                c = s.charAt(idx);
                if (isDigit(c)) {
                    if (isDigit(last)) {
                        nums.push(nums.pop() * 10 + c - '0');
                    } else nums.push(c - '0');
                } else {
                    if (cals.isEmpty()) {
                        cals.push(new Cal(c, true));
                    } else {
                        t = cals.peek();
                        if (t.getPriority() > map.get(c)[0]) {
                            while (t.getPriority() > map.get(c)[0]) {
                                l = cals.pop().calc;
                                b = nums.pop();
                                a = nums.pop();
                                nums.push(calc(a, b, l));
                                if (cals.isEmpty()) {
                                    break;
                                } else {
                                    t = cals.peek();
                                }
                            }
                        } 
                            cals.push(new Cal(c, true));
                    }
                }
                last = c;
                idx++;
            }
            return nums.peek();
        }

        public int  calc(int a, int b, char c) {
            switch (c) {
                case '+':
                    return a + b;
                case '-':
                    return a - b;
                case '*':
                    return a * b;
                case '/':
                    if (b == 0)
                        return Integer.MIN_VALUE;
                    return a / b;
                default:
                    return a + b;
            }
        }

        public boolean isDigit(char c) {
            return c >= '0' && c <= '9';
        }
    }

    @Test
    public void test() {
        String s = "100+100";
        s = "(2*(31-40))*50";
        s = "((10+2)*10-(100-(10+20*10-(2*3)))*10*1*2)-2";
        int res = new Solution1().solve(s);
        System.out.println(res);
    }
}
